[情境任務]
叮咚~!! 有客人進門了!
解師傅:歡迎光臨~這是我們的菜單,要點餐再跟我們說一下~
客人:老闆,你們這菜單怎麼連個數量都沒有啊!!叫我怎麼點呢!
解師傅:阿~~不好意思,我馬上調整!!
上回我們把菜單都給列出來了,但客人想要不只一盤啊!來做個數量欄位吧!
State 代表狀態,useState 是用於管理狀態的 Hook,你可以宣告 state 初始值,並對它進行變更修改,使用 state 進行操作達成想要呈現的畫面
useState
state
狀態state
import { useState } from 'react';
引入 useState
讓整個組件可以使用 useState hook
const [state, setState] = useState(initValue);
state
:狀態變數
setState
:改變 state 值的函式,可以為任何命名,不過一般會以「set + 狀態變數
」的規則命名
initValue
:狀態初始值,可以是任何型態
const [couter, setCouter] = useState(0);
const [userName, setUserName] = useState('Lala');
const [animal, setAnimal] = useState([
{ name: 'cat', age: 12},
{ name: 'dog', age: 6},
{ name: 'mouse', age: 1},
]);
透過解構將 useState
陣列中的值個別取出來,useState
因執行順序,通常會放在函式的最上面,一個組件可以有多個 useState
setState(2);
setState(true);
setState("Lala");
setState(prevValue => prevValue + 1);
setState
裡面會傳入「變更後的值」,可以是一個純值,也可以是一個函式的回傳
為什麼要用函式回傳?
如果我們需要前一次 state 的值,那就需要用函式的方式回傳
由於 setState
是「非同步操作」,我們不能期待連續的 setState 內容會立刻更新,因此將原本傳入的狀態初始值改成傳入一個函式,這個函式參數吃的是原來的 state,以上面的範例來看,state 會等於「原來的 state」 + 1
import { useState } from 'react';
const App = () => {
const [{count1, count2}, setCount] = useState({count1: 0, count2: 10});
const addCount1 = () => {
setCount(state => ({...state, count1: state.count1 + 1}));
}
return (
<div>
<h1>{ count1 }</h1>
<h1>{ count2}</h1>
<button onClick={addCount1}>add</button>
</div>
);
}
export default App;
特別注意的是,如果狀態為一個集合 (object、Array)
setState
需要把原本沒使用到的 state 也合併,否則會出錯
[任務解題]
幫菜單加上數量欄位,我要加 1 再加 1
試著做一個計數器,在 components 資料夾新增一個 Counter.js
組件
components/Counter.js
import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
const addCount = () => {
setCount(state => state + 1)
}
const reduceCount = () => {
setCount(state => state - 1)
}
return (
<span>
<button type='button' onClick={addCount}>+</button>
<button type='button' onClick={reduceCount}>-</button>
<span>{count}</span>
</span>
);
}
export default Counter;
組件裡面有 +
跟 -
的按鈕,用點擊來控制數量
components/List.js
import Counter from "./Counter";
const List = (props) => {
const { name, price, index } = props;
return (
<li>
<span>{index + 1}.</span>
<span>{name}</span>
<span>${price}</span>
<Counter />
</li>
);
};
export default List;
因為每個項目都需要數量,在 List 的地方引入 Counter
App.js
import List from "./components/List";
function App() {
const menu = [
{ name: "蘆筍沙拉", price: 100 },
{ name: "辣炒空心菜", price: 120 },
{ name: "雞蛋豆腐", price: 150 },
{ name: "鳳梨蝦球", price: 300 },
{ name: "糖醋雞丁", price: 200 },
{ name: "砂鍋魚頭", price: 500 },
{ name: "竹筍炒肉絲", price: 150 },
{ name: "梨山高麗菜", price: 120 },
{ name: "五更腸旺", price: 250 },
{ name: "客家小炒", price: 250 },
{ name: "三杯杏鮑菇", price: 180 }
];
return (
<div className="App">
<h1>React 熱炒店</h1>
<ul>
{menu.map((item, index) => (
<List
key={item.name}
name={item.name}
price={item.price}
index={index}
></List>
))}
</ul>
</div>
);
}
export default App;
App 原先就有引入 List,維持不變
codesandbox 程式碼範例
數量要多少都可以,這下子可以順利的點餐了!祝福 React 熱炒店生意欣隆
useState 可以定義狀態、更新狀態,且可以為任何型態,管理起來方便很多,明天我們再繼續吧!
本文將同步更新至我的部落格
Lala 的前端大補帖